#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mod_devicetable.h>
#include "light.h"

#define DEVICE_NAME "light"

struct i2c_client *gclient;

int major;
int minor;

struct cdev *cdev;
struct class *cls;
struct device *dev;

int ap3216c_read_data(void);//读取环境光

int light_open (struct inode *inode, struct file *file){
    printk("light_open\n");
    return 0;
}
//用户读
ssize_t light_read (struct file *file, char __user *ubuff, size_t size, loff_t *loff){

    int ret;
    printk("light_read\n");
    if (size > sizeof(light_data)){
        size = sizeof(light_data);
    }
    
    ap3216c_read_data();
    ret = copy_to_user((int *)ubuff, &light_data, size);
    if (ret){
        return -EIO;
    }
    
    //printk("内核读取的数据：%d\n", light_data);
    
    return size;
}
//用户关闭
int light_close(struct inode *inode, struct file *file){
    printk("light_close\n");
    return 0;
}

struct file_operations fops = {
    .open = light_open,
    .read = light_read,
    .release = light_close,
};

/**
  ap3216c设备 的写读
*/
int ap3216c_write_reg(u8 reg, u8 data){
    int ret;
    u8 w_buf[] = { reg, data};
    // 1.封装消息结构体
    struct i2c_msg w_msg = {
        .addr = gclient->addr,
        .flags = 0,
        .len = 2,
        .buf = w_buf,
    };
    // 2.发送消息
    ret = i2c_transfer(gclient->adapter, &w_msg, 1);
    if (ret != 1) {
        printk("i2c_write_reg error\n");
        return -EAGAIN;
    }
    return 0;
}

int ap3216c_read_reg(u8 reg){

    int ret;
    u8 data;
    // 1.封装消息结构体
    struct i2c_msg r_msg[] = {
        [0] = {
            .addr = gclient->addr,
            .flags = 0,
            .len = 1,
            .buf = &reg,
        },
        [1] = {
            .addr = gclient->addr,
            .flags = 1,
            .len = 1,
            .buf = &data,
        }
    };
    // 2.发送消息
    ret = i2c_transfer(gclient->adapter, r_msg, 2);
    if (ret != 2) {
        printk("i2c_read_reg error\n");
        return -EAGAIN;
    }

    return data;
}

/**
 * 数据的读取
*/
int ap3216c_read_data(void){

    u8 low_val, high_val;
    // ALS环境光传感器
    low_val = ap3216c_read_reg(LIGHT_LOW_ADDR);
    high_val = ap3216c_read_reg(LIGHT_HIGH_ADDR);
    light_data = ((uint16_t)high_val << 8) | low_val;

    return 0;
}

/**
 * ap3216c的初始化
*/
int ap3216c_init(void){

    int ret;
    //设置ap3216c初始化 软件复位
    ret = ap3216c_write_reg(0x00, 0x04);
    if (ret < 0){
        printk("1、ap3216c_write_reg error\n");
        return ret;
    }
    mdelay(10); // 延时
    //设置ap3216c系统模式，开启ALS,PS,IR单次模式
    ret = ap3216c_write_reg(0x00, 0x03);
    if (ret < 0){
        printk("2、ap3216c_write_reg error\n");
        return ret;
    }

    return 0;
}

/**
 * 加载驱动开启
*/

int light_probe(struct i2c_client *client, const struct i2c_device_id *id){

    dev_t devno;
    int ret;
    //printk("light_probe\n");
    gclient = client;

    //1、分配对象
    cdev = cdev_alloc();
    if (NULL == cdev){
        ret = -ENOMEM;
        goto err1;
    }
    //2、初始化对象
    cdev_init(cdev, &fops);
    //3、申请设备号
    ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
    if (ret){
        printk("alloc_chrdev_region failed\n");
        goto err2;
    }
    major = MAJOR(devno);
    minor = MINOR(devno);
    //4、添加字符设备驱动
    ret = cdev_add(cdev, MKDEV(major, minor), 1);
    if (ret){
        printk("cdev_add failed\n");
        goto err3;
    }
    //5、自动创建设备节点
    cls = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(cls)){
        printk("class_create failed\n");
        goto err4;
    }
    dev = device_create(cls, NULL, MKDEV(major, minor), NULL, DEVICE_NAME);
    if (IS_ERR(dev)){
        printk("device_create failed\n");
        goto err5;
    }

    // ap3216c硬件初始化
    ret = ap3216c_init();
    if (ret < 0){
        printk("ap3216c_init failed\n");
    }

    return 0;

err5:
    class_destroy(cls);
err4:
    cdev_del(cdev);
err3:
    unregister_chrdev_region(MKDEV(major, minor), 1);
err2:
    kfree(cdev);
err1:
    return ret;
}

/**
 * 关闭
*/
int light_remove(struct i2c_client *client){

    //printk("light_remove\n");
    device_destroy(cls, MKDEV(major, minor));
    class_destroy(cls);
    cdev_del(cdev);
    unregister_chrdev_region(MKDEV(major, minor), 1);
    kfree(cdev);
    return 0;
}

struct of_device_id oftable[] = {
    { .compatible = "hqyj,ap3216" }, /* 匹配兼容性 */
    {},
};
struct i2c_driver light = {
    .probe = light_probe,
    .remove = light_remove,
    .driver = {
        .name = "light",
        .of_match_table = oftable,
    },
};

module_i2c_driver(light);
MODULE_LICENSE("GPL");